#include "PEIncludes.h"

#include "PEAliceSoftImageAjp.h"

#include "PEImage.h"
#include "PEAliceSoftImageJpg.h"

namespace pe
{

	int AliceImageAjpReadHeader(AliceImageAjpHeader* a_Target, PEStream* a_Stream)
	{
		PEStreamRead(a_Stream, a_Target, sizeof(AliceImageAjpHeader), 1);

		if (a_Target->header[0] != 'A' ||
			a_Target->header[1] != 'J' ||
			a_Target->header[2] != 'P' ||
			a_Target->header[3] != 0
		)
		{
			return -1;
		}

		return PE_OK;
	}

	int AliceImageAjpReadData(AliceImageAjp* a_Target, AliceImageAjpHeader* a_Header, PEStream* a_Stream)
	{
		a_Target->header = new AliceImageAjpHeader;
		memcpy(a_Target->header, a_Header, sizeof(AliceImageAjpHeader));

		a_Target->width = a_Header->width;
		a_Target->height = a_Header->height;

		PEStreamSeek(a_Stream, a_Header->data_offset, SEEK_SET);

		a_Target->data_size = a_Header->data_length;
		a_Target->data = new byte[a_Target->data_size];

		PEStreamRead(a_Stream, a_Target->data, 1, a_Target->data_size);

		static const unsigned char KEY[] = { 
			0x5D, 0x91, 0xAE, 0x87, 
			0x4A, 0x56, 0x41, 0xCD, 
			0x83, 0xEC, 0x4C, 0x92, 
			0xB5, 0xCB, 0x16, 0x34 
		};

		for (unsigned long i = 0; i < sizeof(KEY); i++) {
			a_Target->data[i] ^= KEY[i];
		}

		return PE_OK;

		/*
				AJP_header_t *ajp_header = (AJP_header_t *)raw;
		if (raw_len < 36 || ajp_header->version) {
			delete [] raw;
			return -CUI_EMATCH;
		}

		if (!ajp_header->data_length || !ajp_header->alpha_length) {
			if (ajp_header->alpha_length > 0 && ajp_header->alpha_offset >= 0 
					&& ajp_header->alpha_offset < raw_len) {
				BYTE *unknown1 = raw + ajp_header->alpha_offset;
				decode(unknown1);
				BYTE *act_data = new BYTE[ajp_header->alpha_length];
				if (!act_data) {
					delete [] raw;
					return -CUI_EMEM;
				}
				memcpy(act_data, unknown1, ajp_header->alpha_length);
				delete [] raw;
				raw = act_data;
				raw_len = ajp_header->alpha_length;
				goto retry;
			}

			if (ajp_header->data_length > 0 && ajp_header->data_offset >= 0 
					&& ajp_header->data_offset < raw_len) {
				BYTE *unknown0 = raw + ajp_header->data_offset;
				decode(unknown0);
				BYTE *act_data = new BYTE[ajp_header->data_length];
				if (!act_data) {
					delete [] raw;
					return -CUI_EMEM;
				}
				memcpy(act_data, unknown0, ajp_header->data_length);
				delete [] raw;
				raw = act_data;
				raw_len = ajp_header->data_length;
				goto retry;
			}
		} else {
			decode(raw + ajp_header->data_offset);
			decode(raw + ajp_header->alpha_offset);
			pkg_res->raw_data = raw;
			pkg_res->raw_data_length = raw_len;			
		}
		*/
	}

	PE_EXPORT int AliceImageAjpToRaw(PEImageRaw* a_Target, AliceImageAjp* a_Image)
	{
		// check if jpg

		PEStream read;
		PEStreamByteOpen(&read, a_Image->data, a_Image->data_size);

		AliceImageJpg data_jpg;
		AliceImageJpgHeader header_jpg;
		if (AliceImageJpgReadHeader(&header_jpg, &read) == PE_OK)
		{
			AliceImageJpgReadData(&data_jpg, &header_jpg, &read);
			AliceImageJpgToRaw(a_Target, &data_jpg);

			return PE_OK;
		}

		// uncompressed

		/*a_Target->width = a_Image->width;
		a_Target->height = a_Image->height;
		a_Target->data = new pe::byte[a_Target->width * a_Target->height * 4];
		a_Target->bpp = 8;*/

		PEImageRawCreate(a_Target, a_Image->width, a_Image->height);

		byte* dst = a_Target->data;
		byte* src = a_Image->data;

		for (unsigned int i = 0; i < a_Image->width * a_Image->height; i++)
		{
			dst[0] = src[0];
			dst[1] = src[1];
			dst[2] = src[2];
			dst[3] = 255;

			dst += 4;
			src += 3;
		}

		return PE_OK;
	}

	PE_EXPORT int AliceImageAjpReadAndDecrypt(PEImageRaw* a_Target, PEStream* a_Stream)
	{
		AliceImageAjpHeader header;
		if (AliceImageAjpReadHeader(&header, a_Stream) != PE_OK) 
		{ 
			AliceImageAjpDeleteHeader(&header);
			PEStreamClose(a_Stream);
			return -1; 
		}

		AliceImageAjp image;
		if (AliceImageAjpReadData(&image, &header, a_Stream) != PE_OK) 
		{ 
			AliceImageAjpDeleteHeader(&header);
			AliceImageAjpDeleteData(&image);
			PEStreamClose(a_Stream);
			return -1; 
		}

		if (AliceImageAjpToRaw(a_Target, &image) != PE_OK) 
		{ 
			AliceImageAjpDeleteHeader(&header);
			AliceImageAjpDeleteData(&image);
			PEStreamClose(a_Stream);
			return -1; 
		}

		AliceImageAjpDeleteHeader(&header);
		AliceImageAjpDeleteData(&image);
		PEStreamClose(a_Stream);

		return PE_OK;
	}

	PE_EXPORT int AliceImageAjpDeleteHeader(AliceImageAjpHeader* a_Header)
	{
		return PE_OK;
	}

	PE_EXPORT int AliceImageAjpDeleteData(AliceImageAjp* a_Image)
	{
		delete a_Image->data;

		return PE_OK;
	}

	ImageAliceSoftAjp::ImageAliceSoftAjp()
	{

	}

	ImageAliceSoftAjp::~ImageAliceSoftAjp()
	{

	}

	int ImageAliceSoftAjp::LoadHeader(PEStream* a_Stream)
	{
		m_Stream = a_Stream;
		if (AliceImageAjpReadHeader(&m_Header, a_Stream) == PE_OK)
		{
			return PE_OK;
		}

		return -1;
	}

	int ImageAliceSoftAjp::LoadBody()
	{
		AliceImageAjp ajp_data;
		AliceImageAjpReadData(&ajp_data, &m_Header, m_Stream);

		m_Data = new PEImageRaw;
		AliceImageAjpToRaw(m_Data, &ajp_data);

		AliceImageAjpDeleteData(&ajp_data);
		AliceImageAjpDeleteHeader(&m_Header);

		return PE_OK;
	}

};